【AWS】SQSキューの前には難しいこと考えずにSNSトピックを挟むと良いよ、という話
よく訓練されたアップル信者、都元です。SQSはみなさん使われていますでしょうか。複数のコンポーネント間の疎結合を保ち、バッチ処理等の冗長性・拡張性を確保するために必要不可欠なサービスです。
SQSの活用イメージにつきましては、AWSでジョブWorkerを構成するベストプラクティスのSQSの巻やBeanstalk worker tierの巻をご覧いただくと良いと思います。
さて。SQSを使うぞ、ということになった場合。メッセージを投げる側(=プロデューサ)と、メッセージを受け取る側(=コンシューマ)が必要です。どこかから持ってくる(実装済みの既成品を探してくる)か、もしくは自分自身で実装するわけです。
もちろん、プロデューサはSQSのインターフェイス(API)を理解し(依存し)ていなければなりません。要するに、キューにメッセージを投入する方法を知っており、それを使ってメッセージを投げるような実装になっていなければなりません。同じように、コンシューマもSQSのインターフェイス(API)を理解し(依存し)ていなければなりません。要するに、キューにからメッセージを取得する方法に沿って処理を実装しなければなりません *1。
で。構成として「プロデューサ → SQS queue → コンシューマ」というのがシンプルで直球の実装であることには同意します。ですが本稿タイトルで主張しているのは「プロデューサ → SNS topic → SQS queue → コンシューマ」という形が良いよ、ということです。
えー、なんでそんなことを…。
ですよね。とりあえずこうすることによるデメリットを考えてみましょう。
- SNS topicの構築(SQSとの連携設定等)の手間が増える
- コンポーネントが増え、複雑性が増すため、トラブルの原因が増える
- SNSの課金が余計に掛かる
まぁ、こういったデメリットは確かにあります。他にもあるかもしれません。思いついた方がいましたら教えて下さい。SQSのみを利用する構成からこの構成に移行する場合、プロデューサ側の改修が必要となるでしょう。ただ、依存が増えるわけではなく、SQSへの依存がSNSへの依存に変わるだけです。メッセージの送り方がSNS topicへのメッセージ投入方法に変わるだけです。
個人的な感覚に過ぎませんが、大して重大なデメリットは無いと思っています。手間に関しては私は慣れてますし(ぇ)、トラブルの経験もないですし、SNSの課金はむしろ安すぎてビックリですし。
一方、この構成のメリット
を考えてみましょう。
より抽象的
SNSにメッセージを送るプロデューサは、プロデューサのコードを改修することなく、送り先をSQS queue以外に変更できます。例えば「メッセージをメールとしてどこかに配信する」「Webサーバに対してHTTP POSTを投げる」等への変更が可能です。
一方、SQSにメッセージを投げるプロデューサは、改修を避けることができません。意地でも改修を避けるのであれば、queueからメッセージを受け取ってメールを送信するコンシューマを追加実装するハメになります。
というわけで、SQSに直接メッセージを投げるより、ひとまずSNSにメッセージを投げる実装のほうが抽象的で、高い拡張性を持つことが分かります。
ドレーニングポイント
プロデューサとコンシューマが両者とも(ある程度)健全に動いている時、queueを通過するメッセージを観察するのは困難です。プロデューサにより投入されたメッセージは、瞬時にコンシューマに受信され、メッセージはinvisibleとなります。この瞬間を突いてメッセージを見ることは困難を極めることでしょう。
invisibleの状態のメッセージは、外部から観察することができませんが、SNSをはさんで置くことにより、SQSにメッセージを送りつつ、同時に自分のメールアドレスにメッセージを送らせる等の方法により、キューに入ったメッセージを観察することができます。
拡張ポイント
初期に設計をした時点では、メッセージはキューに入れば万事OKだったかもしれません。仮に「キューに入れつつ、かつ、HTTPサーバにPOSTもしてほしい」とか「複数のキューに同じメッセージを入れたい」となった場合。これもSQSに直接メッセージを投入する場合、プロデューサの改修を避けることができません。
ご想像の通り、SNSをはさんで置けば、SNSのsubscriptionを追加するだけで対応が完了します。
まとめ
というわけで、主にプロデューサ側の安定性を高める効果があるため、SQSを使う場合は手前にSNSを置いておくと良いと思っています。まぁ一部YAGNIに反する考え方ではありますが、それを理解した上で、お勧めです。
脚注
- Beanstalk worker tier内で動いているaws-sqsdを利用する前提であれば、コンシューマ側はHTTP POSTを受け取れれば良いので、SQSに依存する必要はありませんが。が、これは単にアダプタ(ラッパー)を噛ましただけですね。 ↩